package com.zzl.admin.config.shiro;

import com.zzl.admin.entity.admin.Resource;
import com.zzl.admin.entity.admin.Role;
import com.zzl.admin.entity.admin.User;
import com.zzl.admin.service.admin.UserService;
import com.zzl.admin.utils.EmptyUtil;
import com.zzl.admin.utils.EqualsUtil;
import com.zzl.admin.utils.MD5Utils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * Description：我的身份验证
 * Created by 朱正磊 on 2019-03-25 13:53
 */
@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
    private UserService userService;

    @Autowired
    public MyRealm() {
        super(new AllowAllCredentialsMatcher());
        setAuthenticationTokenClass(UsernamePasswordToken.class);
        setCachingEnabled(false); //暂时禁用Cache
    }

    /**
     * description：获取身份信息，我们可以在这个方法中，从数据库获取该用户的权限和角色信息
     * user 朱正磊
     * time 2019-03-25 13:57
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取用户信息
        User user = (User) principalCollection.getPrimaryPrincipal();
        User dbUser = userService.findByUserName(user.getUserName());

        //资源key集合
        Set<String> sourceKeySet = new HashSet<>();
        //角色key集合
        Set<String> roleKeySet = new HashSet<>();
        //用户拥有的角色
        Set<Role> roles = dbUser.getRoles();

        //传统写法
        /*for (Role role : roles) {
            Set<Resource> resources = role.getResources();
            for (Resource resource : resources) {
                sourceKeySet.add(resource.getSourceKey());
            }
            roleKeySet.add(role.getRoleKey());
        }*/

        //lambda写法
        roles.stream().map(Role::getRoleKey).forEach(roleKeySet::add); //往roleKeySet里面添加roleKey
        roles.stream().map(Role::getResources) //往sourceKeySet里面添加sourceKey
                .forEach(e -> e.stream().map(Resource::getSourceKey).forEach(sourceKeySet::add));

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setStringPermissions(sourceKeySet);
        authorizationInfo.setRoles(roleKeySet);
        return authorizationInfo;
    }

    /**
     * description：在这个方法中，进行身份验证
     * user 朱正磊
     * time 2019-03-25 13:58
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取登录页面传过来的用户名和密码
        String username = (String) authenticationToken.getPrincipal();
        String password = new String((char[]) authenticationToken.getCredentials());

        //根据用户名查询数据库用户数据
        User user = userService.findByUserName(username);

        if (EmptyUtil.isEmpty(user)) { //用户名不存在
            throw new UnknownAccountException("用户名或密码不正确！");
        }
        if (EqualsUtil.notEquals(user.getPassword(), MD5Utils.md5(password))) { //密码错误
            throw new IncorrectCredentialsException("用户名或密码不正确！");
        }
        if (EqualsUtil.equals(1, user.getLocked())) { //账号被锁定
            throw new LockedAccountException("账号已被锁定，请联系管理员！");
        }

        return new SimpleAuthenticationInfo(user, username, password);
    }

}
